Evict larger limits first using spill weights#249
Evict larger limits first using spill weights#249cfallin merged 1 commit intobytecodealliance:mainfrom
Conversation
Consider an instruction that could potentially overallocate to a limited range of registers: ``` Use: v0i limit(0..=1), Use: v0i limit(0..=1), Use: v1i limit(0..=7) ``` Both uses of `v0` _must_ fit in registers 0-1 and `v1` should find its home somewhere else in registers 2-7. But fuzzing found a case where this failed. If `v1` was allocated first--say to register 0--and one of the uses of `v0` allocated to the remaining register--register 1--the final use of `v0` had nowhere to go _and_ could not evict either of the previous allocations. This caused `ion` to fail with `TooManyLiveRegs` when in fact a solution was possible. (Why are the identical uses of `v0` allocated separately? Can't they use the same register? I'm not entirely sure, but I think `ion` had split things down to minimal bundles). The fix in this change is to alter the default spill weights assigned to a minimal bundle. Previously, minimal bundles with a fixed constraint received the highest weight, followed by other minimal bundles and then non-minimal bundles. This reserves weights for limits into that order: - minimal with `fixed` constraint - minimal with `limit(0..=0)` constraint - minimal with `limit(0..=1)` constraint - ... - minimal with `limit(0..=255)` constraint - minimal, any other constraint - non-minimal Doing this allows `ion` to evict bundles with higher limits (e.g., `v1i limit(0..=7)` once they become minimal, allowing allocation to continue. Co-authored-by: Chris Fallin <chris@cfallin.org> Co-authored-by: Rahul Chaphalkar <rahul.s.chaphalkar@intel.com>
|
No hurry to merge this just yet; I'm running this in my branch that enables fuzzing of limits: |
|
Also, if it is helpful, I can include an extra commit here with a unit test that runs the exact test case that caused the original problem: |
cfallin
left a comment
There was a problem hiding this comment.
LGTM (no surprise since we pair-programmed this fix) -- thanks a bunch for working on this!
Regarding the unit test for this case -- I guess it depends on whether the fuzzer would cover this (ie the reason we don't have a test suite otherwise, since the fuzzer coverage is so good). This case was originally discovered via fuzzing and the original fuzzbug is now fixed? If so then I think it's fine; otherwise it might be good to throw in an explicit test. Thanks!
|
It's been a bit and this change still looks right to me, so I'm going to go ahead and take this out of draft mode and merge. Thanks again! |
Includes bytecodealliance#249.
|
@cfallin, apologies for not following up with the fuzzing results. I did run fuzzing for this change using fuzz-limit-constraints-rebased and found a fuzz bug that was unrelated to this change. IIRC, the test case did not even have |
|
After looking around I cannot find the |
Consider an instruction that could potentially overallocate to a limited range of registers:
Both uses of
v0must fit in registers 0-1 andv1should find its home somewhere else in registers 2-7. But fuzzing found a case where this failed. Ifv1was allocated first--say to register 0--and one of the uses ofv0allocated to the remaining register--register 1--the final use ofv0had nowhere to go and could not evict either of the previous allocations. This causedionto fail withTooManyLiveRegswhen in fact a solution was possible.(Why are the identical uses of
v0allocated separately? Can't they use the same register? I'm not entirely sure, but I thinkionhad split things down to minimal bundles).The fix in this change is to alter the default spill weights assigned to a minimal bundle. Previously, minimal bundles with a fixed constraint received the highest weight, followed by other minimal bundles and then non-minimal bundles. This reserves weights for limits into that order:
fixedconstraintlimit(0..=0)constraintlimit(0..=1)constraintlimit(0..=255)constraintDoing this allows
ionto evict bundles with higher limits (e.g.,v1i limit(0..=7)once they become minimal, allowing allocation to continue.